#include "AlmacenamientoIndice.h"
#include <iostream>

int AlmacenamientoIndice::codigoArchivo = 0;
int AlmacenamientoIndice::codigoArchivoNivel1 = 0;

using namespace std;

// CONSTRUCTOR
AlmacenamientoIndice::AlmacenamientoIndice(char * modo, int nivel, bool parcial) {
	
	string nombreArchivoIndice;
	
	stringstream cod_str;
	
	destroy = false;
	
	nombreArchivoIndice = Entorno::Instance().getDataPath();
	nombreArchivoIndice += NOMBRE_ARCHIVO_INDICE;
	
	if (parcial) {

		if (nivel == 0) {
			AlmacenamientoIndice::codigoArchivo++;
			nombreArchivoIndice += "_N0_";
			cod_str << codigoArchivo;
		} else {
			AlmacenamientoIndice::codigoArchivoNivel1++;
			nombreArchivoIndice += "_N1_";
			cod_str << codigoArchivoNivel1;
		}

		nombreArchivoIndice += cod_str.str();
	}
	
	nombreArchivoIndice += EXT_ARCHIVO;
	nombreArchivoAlmInd = new char[nombreArchivoIndice.size() + 1];
	strcpy(nombreArchivoAlmInd, nombreArchivoIndice.c_str());
	//std:://cout << "AlmacenamientoIndice.cpp,38: nombreArchivoAlmInd: " << nombreArchivoAlmInd << std::endl;

	strcpy (this->modo, modo);
	cantRegistros = 0;
	archivoIndice = NULL;
}

// DESTRUCTOR
AlmacenamientoIndice::~AlmacenamientoIndice() {

	if (archivoIndice != NULL) {
		fseek(archivoIndice, 0, SEEK_SET);
		fwrite((void *) &cantRegistros, sizeof(int), 1, archivoIndice);
		fclose(archivoIndice);
	}

	if (destroy)
		remove (nombreArchivoAlmInd);
	
	delete [] nombreArchivoAlmInd;
}

void AlmacenamientoIndice::abrirArchivo() {

	archivoIndice = fopen(nombreArchivoAlmInd, modo);

	if (strcmp(modo, CREAR) == 0)
		fwrite((void *) &cantRegistros, sizeof(int), 1, archivoIndice);
		
	if (strcmp(modo, ABRIR) == 0)
		fread((void *) &cantRegistros, sizeof(int), 1, archivoIndice);

	// Actualizar el valor del header al terminar de escribir el archivo
	// de indice
}

// LEE UN REGISTRO DEL INDICE
RegistroIndice * AlmacenamientoIndice::leerRegistroIndice(int posicion)
{
	RegistroIndice * regIndice = NULL;
	int off_lex, off_docs, frec;
	
	// posicionamiento en el archivo
	if (fseek(archivoIndice, sizeof(int) + (RegistroIndice::sizeOf() * posicion), SEEK_SET) == -1)
		return NULL;	
	
	// lectura del registro	
	fread((void *) &off_lex, sizeof(int), 1, archivoIndice);
	fread((void *) &off_docs, sizeof(int), 1, archivoIndice);
	fread((void *) &frec, sizeof(int), 1, archivoIndice);
	
	if (feof(archivoIndice))
		return NULL;
		
	regIndice = new RegistroIndice();
	
	regIndice->setOffsetLexico(off_lex);
	regIndice->setOffsetDocs(off_docs);
	regIndice->setFrecuencia(frec);
	
	return regIndice;
}

// LEE EL SIGUIENTE REGISTRO
RegistroIndice * AlmacenamientoIndice::leerSiguiente()
{
	RegistroIndice * regIndice = NULL;
	int off_lex, off_docs, frec;
	
	// lectura del registro	
	fread((void *) &off_lex, sizeof(int), 1, archivoIndice);
	fread((void *) &off_docs, sizeof(int), 1, archivoIndice);
	fread((void *) &frec, sizeof(int), 1, archivoIndice);
	
	if (feof(archivoIndice))
		return NULL;
		
	regIndice = new RegistroIndice();
	
	regIndice->setOffsetLexico(off_lex);
	regIndice->setOffsetDocs(off_docs);
	regIndice->setFrecuencia(frec);
	
	return regIndice;
}

// ESCRIBE UN REGISTRO DEL INDICE
void AlmacenamientoIndice::escribirRegistroIndice(RegistroIndice * regIndice) {

	int off_lex, off_docs, frec;

	off_lex = regIndice->getOffsetLexico();
	off_docs = regIndice->getOffsetDocs();
	frec = regIndice->getFrecuencia();
	
	fwrite((void *) &off_lex, sizeof(int), 1, archivoIndice);
	fwrite((void *) &off_docs, sizeof(int), 1, archivoIndice);
	fwrite((void *) &frec, sizeof(int), 1, archivoIndice);

	cantRegistros++;
}

void AlmacenamientoIndice::resetearCodigoArchivo() {
	AlmacenamientoIndice::codigoArchivo = 0;
}

void AlmacenamientoIndice::resetearCodigoArchivoNivel1() {
	AlmacenamientoIndice::codigoArchivoNivel1 = 0;
}

// setea la variable que indica si el archivo al cerrarse, debe ser destruido
void AlmacenamientoIndice::setDestroy() {
	destroy = true;
}

// renombra el archivo para tener su nombre final (sin niveles)
void AlmacenamientoIndice::renombrarArchivoFinal () {
	
	string nombreArchivoFinal;
	
	nombreArchivoFinal = Entorno::Instance().getDataPath();
	nombreArchivoFinal += NOMBRE_ARCHIVO_INDICE;
	nombreArchivoFinal += EXT_ARCHIVO;
	
	rename (nombreArchivoAlmInd, nombreArchivoFinal.c_str());
	delete [] nombreArchivoAlmInd;
	nombreArchivoAlmInd = new char[nombreArchivoFinal.size() + 1];
	strcpy(nombreArchivoAlmInd, nombreArchivoFinal.c_str());
	//cout << "AlmacenamientoIndice.cpp,166: nombreArchivoAlmInd: " << nombreArchivoAlmInd << endl;
}

// renombra el archivo al nivel que se pide
void AlmacenamientoIndice::renombrarArchivoANivel (char * nivel) {

	string nombreArchivoIndice;
	stringstream cod_str;

	if (strcmp (nivel, NIVEL_0) == 0) 
		cod_str << ++codigoArchivo;
	else
		cod_str << ++codigoArchivoNivel1;
			
	nombreArchivoIndice = Entorno::Instance().getDataPath();
	nombreArchivoIndice += NOMBRE_ARCHIVO_INDICE;
	nombreArchivoIndice += nivel;
	nombreArchivoIndice += cod_str.str();
	nombreArchivoIndice += EXT_ARCHIVO;

	rename (nombreArchivoAlmInd, nombreArchivoIndice.c_str());
	delete [] nombreArchivoAlmInd;
	nombreArchivoAlmInd = new char[nombreArchivoIndice.size() + 1];
	strcpy(nombreArchivoAlmInd, nombreArchivoIndice.c_str());
	//cout << "AlmacenamientoIndice.cpp,190: nombreArchivoAlmInd: " << nombreArchivoAlmInd << endl;
}

int AlmacenamientoIndice::getCodigoArchivo() {
	return codigoArchivo;
}

int AlmacenamientoIndice::getCantidadRegistros() {
	return this->cantRegistros;
}
